; File:  fact.y.

; Here's the chosen function.

(define fact 
  (lambda (n)
    (if (zero? n)
        1
        (* n (fact (- n 1))))))
;
(fact 5)
;
(define identity
  (lambda (x) x))
;
(define project-1st-of-2
  (lambda (x)
    (lambda (y)
      x)))
;
(define project-2nd-of-2
  (lambda (x)
    identity))
;
(define project-3rd-of-3
  (lambda (x)
    (lambda (y)
      identity)))
;
;
; true and false could be defined this way:
;
(define combinator-true
  project-1st-of-2)
;
(define combinator-false
  project-2nd-of-2)
;
; but we'll do them as follows.
;
(define combinatorÐtrue
	(lambda (x)
		(lambda (y)
			x)))

;
(define combinatorÐfalse
	(lambda (x)
		(lambda (y)
			y)))

;
(define combinator-cons
  (lambda (x)
    (lambda (y)
      (lambda (selector)
        ((selector x) y)))))
;
(define combinator-car
  (lambda (object)
    (object project-1st-of-2)))
;
(define combinator-cdr
  (lambda (object)
    (object project-2nd-of-2)))
;
(define force-a-thunk
  (lambda (thunk)
    (thunk)))
;
(define combinator-if
  (lambda (condition)
    (lambda (then)
      (lambda (else)
        (force-a-thunk ((condition then) else))))))
;
(define combinator-zero
  project-2nd-of-2)
;
(define combinator-zero?
  (lambda (n)
    ((n project-3rd-of-3) combinator-true)))
;
(define combinator-succ
  (lambda (n)
    (lambda (f)
      (lambda (x)
        (f ((n f) x))))))
;
(define dechurchify-numeral
  (lambda (numeral)
    ((numeral 1+) 0)))
;
(define make-church-numeral
  (lambda (n)
    (if (zero? n)
        combinator-zero
        (combinator-succ 
         (make-church-numeral (- n 1))))))
;
(define combinator-*
  (lambda (m)
    (lambda (n)
      (lambda (f)
        (m (n f))))))
;
(define combinator-pred
  (lambda (n)
    (combinator-car 
     ((n (lambda (tuple)
           ((combinator-cons 
             (combinator-cdr tuple))
            (combinator-succ (combinator-cdr tuple)))))
      ((combinator-cons "combinator-pred called on 0")
       combinator-zero)))))
;
(define combinator-applicative-order-y
  (lambda (f)
    ((lambda (x) (f (lambda (arg) ((x x) arg))))
     (lambda (x) (f (lambda (arg) ((x x) arg)))))))
; 
(define combinator-one
  (make-church-numeral 1))
;
(define combinator-fact
  (combinator-applicative-order-y 
   (lambda (fact)
     (lambda (n)
       (((combinator-if (combinator-zero? n))
         (lambda () combinator-one))
        (lambda () ((combinator-* n) 
                    (fact (combinator-pred n)))))))))
;
(dechurchify-numeral 
 (combinator-fact (make-church-numeral 5)))
;
; Done.
